# -*- coding: utf-8 -*-

import hashlib
import string
import random
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
import base64
from .exception import ServerError, ClientError, BizResponseError
from . import config


def status_code_checker(resp):
    status_code = resp.status_code
    if 200 <= status_code <= 299:
        return True
    elif status_code >= 500:
        raise ServerError(status_code)
    elif status_code == 400:
        raise ClientError("Bad Request")
    elif status_code == 401:
        raise ClientError("Unauthorized Access")
    elif status_code == 403:
        raise ClientError("Forbidden Access")
    elif status_code == 404:
        raise ClientError("Resource Not Found")
    elif status_code == 405:
        raise ClientError("Method Not Allowed")
    elif status_code == 409:
        raise ClientError("Resource Conflict")
    elif status_code == 410:
        raise ClientError("Resource Gone")
    elif status_code == 422:
        raise ClientError("Resource Invalid")
    elif status_code >= 400:
        raise ClientError('status code: %d' % status_code)
    elif status_code in (301, 302, 303, 307):
        raise RuntimeError('Redirection')
    else:
        raise RuntimeError('status code: %d' % status_code)


def result_code_checker(j):
    """
    检查支付网关2.0的响应中最外层的result_code值,当不等于200时抛出异常
    :param j:
    :return:
    """
    if j['result_code'] != '200':
        raise BizResponseError(j)


def gen_rand_str(length=8, s_type='mixed', prefix=None, postfix=None):
    """
    生成指定长度的随机数，可设置输出字符串的前缀、后缀字符串
    :param length: 随机字符串长度
    :param s_type:
    :param prefix: 前缀字符串
    :param postfix: 后缀字符串
    :return:
    """
    if s_type == 'digit':
        s = string.digits
    elif s_type == 'ascii':
        s = string.ascii_letters
    elif s_type == 'hex':
        s = '0123456789abcdef'
    else:
        s = string.ascii_letters + string.digits

    ret = []
    mid = [random.choice(s) for _ in range(length)]
    if prefix is not None:
        ret.append(prefix)
    ret.extend(mid)
    if postfix is not None:
        ret.append(postfix)
    return ''.join(ret)


def md5_str(content):
    """
    计算字符串的MD5值
    :param content:输入字符串
    :return:
    """
    m = hashlib.md5(content.encode('utf-8'))
    return m.hexdigest()


def verify_signature(body, sign, public_key_pem = config.public_key_pem):
    """
    验证收钱吧回调签名  
    :param sign: 请求头中的签名值(Base64编码字符串)  
    :param body: 原始请求体字节数据  
    :param public_key_pem: PEM格式的公钥字符串  
    :return: 验签结果 (True/False)  
    """
    pubKey = RSA.importKey(public_key_pem) # 获取公钥 11
    h = SHA256.new(body) # 对请求体进行SHA256加密10
    verifier = PKCS1_v1_5.new(pubKey) # 创建验证12
    return verifier.verify(h, base64.b64decode(sign)) # 验证签名是否一致，sign需要base64解密


def generate_signature(params: dict,key: str):
    """
    根据参数生成签名sign  
    """
    filtered_params = {}
    for key_param, value in params.items():
        if key_param in ['sign', 'sign_type']:
            continue
        if isinstance(value, bytes):
            continue
        filtered_params[key_param] = value
    # 排序：按键的ASCII码升序排列
    sorted_items = sorted(filtered_params.items(), key=lambda x: x[0])
    # 拼接参数
    param_pairs = [f"{k}={v}" for k, v in sorted_items]
    string_a = '&'.join(param_pairs)
    # 拼接密钥并生成签名
    string_sign_temp = f"{string_a}&key={key}"
    md5 = hashlib.md5()
    md5.update(string_sign_temp.encode('utf-8'))
    sign = md5.hexdigest().upper()
    return sign